package cn.aezo.minions.web.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetails;

import javax.servlet.http.HttpServletRequest;

/**
 * Created by smalle on 2017/9/14.
 */
// 权限认证：https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#authorization
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true) // 开启方法级别权限控制
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationProvider authProvider; // 提供认证算法(判断是否登录成功)

    @Autowired
    private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource; // 认证信息

    @Autowired
    private AuthenticationSuccessHandler authenticationSuccessHandler; // 用于处理登录成功

    @Autowired
    private AuthenticationFailureHandler authenticationFailureHandler; // 用于处理登录失败

    @Autowired
    private AccessDeniedHandler accessDeniedHandler; // 用于处理无权访问

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authProvider);
    }

    // 定义权限规则
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().disable(); // 解决spring boot项目中出现不能加载iframe
        http.csrf().disable()
            .authorizeRequests()
                .antMatchers("/manage/about", "/manage/404", "/manage/403").permitAll() // 这些端点不进行权限验证
                .antMatchers("/res/**").permitAll() // idea的resources/static目录下的文件夹对应一个端点，相当于可以访问resources/static/res/下所有文件（还有一些默认的端点：/css/**、/js/**、/images/**、/webjars/**、/**/favicon.ico）
                // .antMatchers("/manage/**").hasAnyRole("ADMIN") // 需要有ADMIN角色才可访问/admin（有先后顺序，前面先定义的优先级高，因此比antMatchers("/**").hasAnyRole("USER", "ADMIN")优先级高）
                .antMatchers("/**").hasAnyRole("USER", "ADMIN") // 有USER/ADMIN角色均可
                .anyRequest().authenticated() // (除上述忽略请求)所有的请求都需要权限认证
                .and()
            .formLogin()
                .loginPage("/manage/login").permitAll() // 登录界面(Get)和登录处理方法(Post)
                .successHandler(authenticationSuccessHandler)
                .failureHandler(authenticationFailureHandler)
                .authenticationDetailsSource(authenticationDetailsSource)
                .and()
            .logout().logoutUrl("/manage/logout").logoutSuccessUrl("/manage/login").permitAll()
                .and()
            .exceptionHandling().accessDeniedHandler(accessDeniedHandler);
    }
}

